package org.sample.commons.ftp;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Properties;

import com.jcraft.jsch.SftpException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;

/**
 * 本类实现SFTP文件基础操作功能
 * 非线程安全
 */
public class SFTPClientImpl extends AbstractFTPClient {

    private static final Logger log = LoggerFactory.getLogger(SFTPClientImpl.class);

    private ChannelSftp ftpClient;

    private Session session;

    public SFTPClientImpl(FTPConfig config) throws FTPException {
        super(config);
    }

    /**
     * 连接sftp服务器
     */
    @Override
    public void connect() throws FTPException {
        try {
            JSch jsch = new JSch();
            if (StringUtils.isNotBlank(config.getKeypath())) {
                if (!new File(config.getKeypath()).exists())
                    throw new FTPException("找不到密钥文件" + config.getKeypath());
                // 使用密钥验证方式，密钥可以使有口令的密钥，也可以是没有口令的密钥
                if (StringUtils.isNotBlank(config.getPassphrase())) {
                    jsch.addIdentity(config.getKeypath(), config.getPassphrase());
                } else {
                    jsch.addIdentity(config.getKeypath());
                }
            }

            log.debug("SFTP start");
            session = jsch.getSession(config.getUsername(), config.getHost(), config.getPort());
            if (StringUtils.isNotBlank(config.getPassword()))
                session.setPassword(config.getPassword());

            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            session.setConfig(sshConfig);
            session.setTimeout(config.getTimeout());
            session.connect();
            ftpClient = (ChannelSftp) session.openChannel("sftp");
            ftpClient.connect(config.getTimeout());
            log.debug("SFTP channel connect SUCCESS");
        } catch (Exception e) {
            throw new FTPException("连接SFTP服务器失败", e);
        }
    }

    /**
     * 关闭连接
     */
    @Override
    public void disconnect() {
        log.debug("SFTP disconnect");
        if (ftpClient != null)
            ftpClient.disconnect();
        if (session != null)
            session.disconnect();
    }

    @Override
    public void mkdir(String path) throws FTPException {
        try {
            ftpClient.mkdir(path);
        } catch (SftpException e) {
            throw new FTPException("创建目录失败", e);
        }
    }

    /**
     * 进入到服务器的某个目录下
     */
    @Override
    public void changeDir(String directory) throws FTPException {
        try {
            ftpClient.cd(directory);
        } catch (Exception e) {
            throw new FTPException("切换目录失败", e);
        }
    }

    @Override
    public void upload(File file, String fileName) throws FTPException {
        try {
            ftpClient.put(new FileInputStream(file), fileName);
        } catch (Exception e) {
            throw new FTPException("上传文件失败", e);
        }
    }

    @Override
    public void upload(byte[] bytes, String fileName) throws FTPException {
        try {
            ftpClient.put(new ByteArrayInputStream(bytes), fileName);
        } catch (Exception e) {
            throw new FTPException("上传文件失败", e);
        }
    }

    @Override
    public File download(String ftpFileName, String localFileName) throws FTPException {
        File file = new File(localFileName);
        try {
            ftpClient.get(ftpFileName, new FileOutputStream(file));
            return file;
        } catch (Exception e) {
            file.delete();
            throw new FTPException("下载文件失败", e);
        }
    }

    @Override
    public void download(String ftpFileName, File localFile) throws FTPException {
        try {
            ftpClient.get(ftpFileName, new FileOutputStream(localFile));
        } catch (Exception e) {
            localFile.delete();
            throw new FTPException("下载文件失败", e);
        }
    }

    @Override
    public void delete(String fileName) throws FTPException {
        try {
            ftpClient.rm(fileName);
        } catch (Exception e) {
            throw new FTPException("删除文件失败", e);
        }
    }

    @Override
    public void rename(String oldFileName, String newFileName) throws FTPException {
        try {
            ftpClient.rename(oldFileName, newFileName);
        } catch (Exception e) {
            throw new FTPException("重命名文件失败", e);
        }
    }

}